package me.sdevil507.org.controller;

import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import me.sdevil507.biz.common.exceptions.RoleCodeExistedException;
import me.sdevil507.biz.common.exceptions.RoleNameExistedException;
import me.sdevil507.org.dto.*;
import me.sdevil507.org.mapper.*;
import me.sdevil507.org.po.OrgPo;
import me.sdevil507.org.po.OrgRolePo;
import me.sdevil507.org.po.OrgRoleResourceRelPo;
import me.sdevil507.org.po.OrgUserPo;
import me.sdevil507.org.service.OrgRoleService;
import me.sdevil507.org.service.OrgService;
import me.sdevil507.platform.po.QPlatResourcePo;
import me.sdevil507.platform.service.PlatResourceService;
import me.sdevil507.supports.jpa.PageConvertCallBack;
import me.sdevil507.supports.jpa.PageResultDTO;
import me.sdevil507.supports.jpa.PageResultGenerator;
import me.sdevil507.supports.result.ApiResultDTO;
import me.sdevil507.supports.result.ApiResultGenerator;
import me.sdevil507.supports.shiro.enums.RoleType;
import me.sdevil507.supports.shiro.helper.OrgAccountHelper;
import me.sdevil507.supports.shiro.realm.OrgUsernamePasswordRealm;
import me.sdevil507.supports.status.ApiStatusCode;
import me.sdevil507.supports.status.ComConstant;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 机构角色表[OrgRoleController]
 *
 * @author sdevil507
 * created on 2020-06-23 18:15:44
 */
@RestController
@RequestMapping("/api/org/role")
@Slf4j
public class OrgRoleController {

    @Autowired
    private OrgRoleService orgRoleService;

    @Autowired
    private OrgService orgService;

    @Autowired
    private OrgRoleResourceRelMapper orgRoleResourceRelMapper;

    @Autowired
    private OrgMapper orgMapper;

    @Autowired
    private OrgRoleMapper orgRoleMapper;

    @Autowired
    private OrgUserMapper orgUserMapper;

    @Autowired
    private OrgResourceMapper orgResourceMapper;

    @Autowired
    private OrgUsernamePasswordRealm orgUsernamePasswordRealm;

    @Autowired
    private PlatResourceService platResourceService;

    @Autowired
    JPAQueryFactory jpaQueryFactory;

    /**
     * 分页获取信息列表
     *
     * @param dto 入参
     * @return 分页数据
     */
    @SuppressWarnings("Convert2Lambda")
    @RequestMapping(value = "/readAllByPage", method = RequestMethod.POST)
    public ApiResultDTO readAllByPage(@RequestBody OrgRoleMergeParamsDto dto) {
        Page<OrgRolePo> pagePos = orgRoleService.readAllByPage(dto.getSearchDto(), dto.getPageDto(), dto.getSortDto());
        PageResultDTO<OrgRoleResultDto> pageResultDto = PageResultGenerator.convert(pagePos, new PageConvertCallBack<OrgRoleResultDto, OrgRolePo>() {
            @Override
            public List<OrgRoleResultDto> exec(List<OrgRolePo> list) {
                return orgRoleMapper.pos2dtos(list);
            }
        });
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), pageResultDto);
    }

    /**
     * 分页所有角色  区分机构 递归查询
     *
     * @param dto 入参
     * @return 分页数据
     */
    @RequestMapping(value = "/searchOrgAllRoleData", method = RequestMethod.POST)
    public ApiResultDTO searchOrgAllRoleData(@RequestBody OrgRoleParamsDto dto) {
        List<OrgRolePo> result = orgRoleService.searchOrgAllRoleData(dto);
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), orgRoleMapper.pos2dtos(result));
    }

    /**
     * 根据角色id获取用户列表
     *
     * @return 用户列表
     */
    @RequestMapping(value = "/readUsersById", method = RequestMethod.POST)
    public ApiResultDTO readUsersById(@RequestBody OrgRoleParamsDto dto) {
        List<OrgUserPo> list = orgRoleService.readUsersById(dto.getId());
        List<OrgUserResultDto> orgUserResultDtos = orgUserMapper.pos2dtos(list);
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), orgUserResultDtos);
    }

    /**
     * 根据角色id获取资源列表
     *
     * @return 资源列表
     */
    @RequestMapping(value = "/readResourcesById", method = RequestMethod.POST)
    public ApiResultDTO readResourcesById(@RequestBody OrgRoleParamsDto dto) {
        List<OrgRoleResourceRelResultDto> resultDtos = orgRoleResourceRelMapper.pos2dtos(orgRoleService.readResourcesById(dto.getId()));
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), resultDtos);
    }

    /**
     * 根据角色id获取机构列表
     *
     * @return 机构列表
     */
    @RequestMapping(value = "/readOrgListById", method = RequestMethod.POST)
    public ApiResultDTO readOrgListById(@RequestBody OrgRoleParamsDto dto) {
        try {
            List<OrgPo> list = orgRoleService.readOrgsById(dto.getId());
            List<OrgResultDto> orgResultDtoList = orgMapper.pos2dtos(list);
            return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), orgResultDtoList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建
     *
     * @param dto 传输类
     * @return 执行反馈
     */
    @RequiresPermissions(value={"org:role:add","plat:role:add"}, logical= Logical.OR)
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    public ApiResultDTO create(@RequestBody OrgRoleParamsDto dto) {
        try {
            if(dto.getDeptId() == null){
                dto.setDeptId(OrgAccountHelper.getDeptId());
            }
            orgRoleService.create(dto);
        } catch (RoleNameExistedException e) {
            return ApiResultGenerator.create(ApiStatusCode.ROLE_NAME_EXISTED.getCode(), ApiStatusCode.ROLE_NAME_EXISTED.getDescription());
        } catch (RoleCodeExistedException e) {
            return ApiResultGenerator.create(ApiStatusCode.ROLE_CODE_EXISTED.getCode(), ApiStatusCode.ROLE_CODE_EXISTED.getDescription());
        }
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }

    /**
     * 更新
     *
     * @param dto 传输类
     * @return 执行反馈
     */
    @RequiresPermissions(value={"org:role:edit","plat:role:edit"}, logical= Logical.OR)
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public ApiResultDTO update(@RequestBody OrgRoleParamsDto dto) {
        try {
            if(dto.getDeptId() == null){
                dto.setDeptId(OrgAccountHelper.getDeptId());
            }
            orgRoleService.update(dto);
        } catch (RoleNameExistedException e) {
            return ApiResultGenerator.create(ApiStatusCode.ROLE_NAME_EXISTED.getCode(), ApiStatusCode.ROLE_NAME_EXISTED.getDescription());
        } catch (RoleCodeExistedException e) {
            return ApiResultGenerator.create(ApiStatusCode.ROLE_CODE_EXISTED.getCode(), ApiStatusCode.ROLE_CODE_EXISTED.getDescription());
        }
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }

    /**
     * 删除
     *
     * @param dto 传输类
     * @return 执行反馈
     */
    @RequiresPermissions(value={"org:role:delete","plat:role:delete"}, logical= Logical.OR)
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public ApiResultDTO delete(@RequestBody OrgRoleParamsDto dto) {
        orgRoleService.delete(dto);
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }

    /**
     * 角色分配用户
     *
     * @param dto 入参
     * @return 执行反馈
     */
    @RequiresPermissions(value={"org:role:set:user","plat:role:set:user"}, logical= Logical.OR)
    @RequestMapping(value = "/allotUsers", method = RequestMethod.POST)
    public ApiResultDTO allotUsers(@RequestBody OrgRoleAllotUsersParamsDto dto) {
        orgRoleService.allotUsers(dto.getRoleId(), dto.getUserIds());
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }

    /**
     * 角色分配资源
     *
     * @param dto 入参
     * @return 执行反馈
     */
    @RequiresPermissions(value={"org:role:set:module","plat:role:set:module"}, logical= Logical.OR)
    @RequestMapping(value = "/allotResources", method = RequestMethod.POST)
    public ApiResultDTO allotResources(@RequestBody OrgRoleAllotResourcesParamsDto dto) {
        orgRoleService.allotResources(dto);
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }



    /**
     * 角色分配机构
     *
     * @param dto 入参
     * @return 执行反馈
     */
    @RequiresPermissions("org:role:set:org")
    @RequestMapping(value = "/allotOrgs", method = RequestMethod.POST)
    public ApiResultDTO allotOrgs(@RequestBody OrgRoleAllotOrgsParamsDto dto) {
        orgRoleService.allotOrgs(dto.getRoleId(), dto.getOrgIds());

        List<OrgUserPo> users = orgRoleService.readUsersById(dto.getRoleId());
        //更新缓存
        users.forEach(orgUserPo -> {
            //删除用户与机构的权限关系--只包含orgId
            orgRoleService.deleteOrgsOfUserId(orgUserPo.getId());
            //重新添加
            orgRoleService.findOrgs(orgUserPo.getId());

            //test
//            sysdictService.test(platUserPo.getId());
            //test
//            platRoleService.test(platUserPo.getId());

            //删除用户与机构的权限关系--根据机构分类
            orgRoleService.deleteOrgsByClassifyOfUserId(orgUserPo.getId());
            //重新添加
            orgRoleService.findOrgsByClassify(orgUserPo.getId());

            //删除用户与机构类型的对应关系
            orgService.deleteAllOrgTypeOfUserId(orgUserPo.getId());
            //重新添加
            orgService.getAllOrgType(orgUserPo.getId());
        });

        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription());
    }

    /**
     * 获取权限
     *
     * @return 权限集合
     */
    @RequestMapping(value = "/findPermissions", method = RequestMethod.POST)
    public ApiResultDTO findPermissions() {
        //获取用户所有的权限模块
        List<OrgResourceRelDto> orgResourceRelList = orgRoleService.getUserPermissionModule(OrgAccountHelper.getUserId());
        //按钮
        List<OrgResourceRelDto> buttonList = orgResourceRelList.stream().filter(orgResourceRelDto -> ComConstant.ModuleType.MODULE_BUTTON.equals(orgResourceRelDto.getType())).collect(Collectors.toList());
        //菜单
        List<OrgResourceRelDto> orgResourceRelMenuList = orgResourceRelList.stream()
                .filter(orgResourceRelDto -> ComConstant.ModuleType.MODULE_MENU.equals(orgResourceRelDto.getType()))
                .peek(orgResourceRelDto -> {
                    orgResourceRelDto.setChildren(buttonList.stream().filter(btnResource-> btnResource.getParentId().equals(orgResourceRelDto.getId())).collect(Collectors.toList()));
                })
                .collect(Collectors.toList());
        List<OrgResourceRelDto> platformList =  orgResourceRelMenuList.stream().filter(orgResourceRelDto -> ComConstant.ModuleService.PLATFORM == orgResourceRelDto.getServiceClassify()).collect(Collectors.toList());
        List<OrgResourceRelDto> orgList = orgResourceRelMenuList.stream().filter(orgResourceRelDto -> ComConstant.ModuleService.ORGANIZATION == orgResourceRelDto.getServiceClassify()).collect(Collectors.toList());
        List<OrgResourceRelDto> expertList = orgResourceRelMenuList.stream().filter(orgResourceRelDto -> ComConstant.ModuleService.EXPERT == orgResourceRelDto.getServiceClassify()).collect(Collectors.toList());
        List<OrgResourceRelDto> projectList = orgResourceRelMenuList.stream().filter(orgResourceRelDto -> ComConstant.ModuleService.PROJECT == orgResourceRelDto.getServiceClassify()).collect(Collectors.toList());
        List<OrgResourceRelDto> toolList = orgResourceRelMenuList.stream().filter(orgResourceRelDto -> ComConstant.ModuleService.TOOL == orgResourceRelDto.getServiceClassify()).collect(Collectors.toList());

        OrgPermissionResult orgPermissionResult = new OrgPermissionResult();

        //权限结果集
        List<OrgPermissionResult.PermissionResult> permissionResults = new ArrayList<>();

        if(!CollectionUtils.isEmpty(platformList)){
            permissionResults.add(new OrgPermissionResult.PermissionResult("系统管理", "platform", this.sortList(new HashSet<>(platformList))));
        }
        if(!CollectionUtils.isEmpty(orgList)){
            permissionResults.add(new OrgPermissionResult.PermissionResult("智库管理", "org", this.sortList(new HashSet<>(orgList))));
        }
        if(!CollectionUtils.isEmpty(expertList)){
            permissionResults.add(new OrgPermissionResult.PermissionResult("专家管理", "expert", this.sortList(new HashSet<>(expertList))));
        }
        if(!CollectionUtils.isEmpty(projectList)){
            permissionResults.add(new OrgPermissionResult.PermissionResult("课题管理", "project", this.sortList(new HashSet<>(projectList))));
        }
        if(!CollectionUtils.isEmpty(toolList)){
            permissionResults.add(new OrgPermissionResult.PermissionResult("其他工具", "tool", this.sortList(new HashSet<>(toolList))));
        }
        orgPermissionResult.setPermissionResultList(permissionResults);
        orgPermissionResult.setButtonResultList(new OrgPermissionResult.PermissionResult(buttonList));

        //专家  默认给专家端菜单权限
        if(RoleType.EXPERT.name().equals(OrgAccountHelper.getOrgType())){
            List<OrgResourceRelDto> expertModuleList = platResourceService.readAllExpertModuleData();
            if(!CollectionUtils.isEmpty(expertModuleList)){
                permissionResults.add(new OrgPermissionResult.PermissionResult("专家模块", "expert", this.sortList(new HashSet<>(expertModuleList))));
            }
        }

        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), orgPermissionResult);
    }

    //排序
    public List<OrgResourceRelDto> sortList(Set<OrgResourceRelDto> setList){
        List<OrgResourceRelDto> list = new ArrayList<OrgResourceRelDto>(setList);
        list = list.stream().sorted(Comparator.comparing(OrgResourceRelDto::getSortNum)).collect(Collectors.toList());
        list.sort((s1, s2) -> Boolean.compare(s2.getModuleAuth(), s1.getModuleAuth()));
        return list;
    }

}